﻿using Reflexive.IO;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks;
using ZeroMQ;

namespace Reflexive.IO
{
    public partial class ZeroWriter<TConverter, TSource> : IObserver<TSource>
        where TConverter : ITypeConverter<TSource, byte[]>, new()
    {
        ZmqSocket _socket;
        ZmqContext _context;
        IEnumerable<string> _endpoints;

        public StatusCode Status
        {
            get;
            private set;
        }

        public ZeroWriter(IEnumerable<string> endpoints)
        {
            _endpoints = endpoints;
            _context = ZmqContext.Create();
            _socket = _context.CreateSocket(SocketType.PUB);
            foreach (var endpoint in _endpoints)
                _socket.Bind(endpoint);
        }

        public void Stop()
        {
            Status = StatusCode.Suspended;
        }

        public void Start()
        {
            if (Status == StatusCode.Completed)
            {
                throw new NotSupportedException("Writer is in the Completed state.");
            }

            Status = StatusCode.Started;
        }

        public void OnCompleted()
        {
            if (Status != StatusCode.Completed)
            {
                try
                {
                    foreach (var endpoint in _endpoints)
                    {
                        try
                        {
                            _socket.Disconnect(endpoint);
                        }
                        catch (Exception e)
                        {
                            System.Diagnostics.Trace.TraceError(e.ToString());
                        }
                    }
                    _socket.Dispose();
                    _context.Dispose();
                }
                catch (Exception e)
                {
                    System.Diagnostics.Trace.TraceError(e.ToString());
                }
                finally
                {
                    Status = StatusCode.Completed;
                }
            }
        }

        public void OnError(Exception error)
        {
            System.Diagnostics.Trace.TraceError(error.ToString());
        }

        public void OnNext(TSource value)
        {
            if (Status == StatusCode.Started)
            {
                _socket.Send((Convertible<TConverter, TSource, byte[]>)value);
            }
        }

        public void Dispose()
        {
            OnCompleted();
        }

    }
}
